package cn.xsirl.websocket.handler;

import cn.xsirl.websocket.manager.ChatRoomManager;
import cn.xsirl.websocket.message.ComponentMessage;
import cn.xsirl.websocket.util.BaseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.AbstractWebSocketHandler;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.List;

import static cn.xsirl.websocket.util.WebSocketUtil.*;

@Component
public class ChatRoom extends AbstractWebSocketHandler {

    private static Logger log = LoggerFactory.getLogger(ChatRoom.class);
    
    /**
     * 建立连接后执行
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        ChatRoomManager.add(session.getId(), session);
        
        log.info("----------- 有新用户加入连接 -----------");
        log.info("会话id: {}", session.getId());
        log.info("接受的协议: {}", session.getAcceptedProtocol());
        log.info("远程地址：{}", session.getRemoteAddress().getHostName() + ":" + session.getRemoteAddress().getPort());
        log.info("允许的二进制消息最大限制：{}", session.getBinaryMessageSizeLimit());
        log.info("允许的文本消息最大限制：{}", session.getTextMessageSizeLimit());
        log.info("\n");
    }
    
    /**
     * 处理文本消息
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("--------------- 收到文本消息 ---------------");
        log.info("消息长度：{}", message.getPayloadLength());
        ChatRoomManager.broadcast(message);
    }
    
    /**
     * 处理二进制消息
     */
    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
        log.info("--------------- 收到二进制消息 ---------------");
        log.info("数据包总字节数：{}", message.getPayloadLength());
        log.info("\n");
        
        
        List<ComponentMessage> msgList = decode(message.getPayload());
        if(msgList.size() < 2) {
            ComponentMessage componentMessage = msgList.get(0);
            ChatRoomManager.broadcast(new BinaryMessage(encode(componentMessage)));
        } else {
            
            // 多条消息处理规则不清楚
            
            // 暂时简单做个加法运算，实际可能更复杂
            ComponentMessage a = msgList.get(0);
            ComponentMessage b = msgList.get(1);
            ComponentMessage c = msgList.get(2);
            
            // 需要一个消息处理规则
            // 先简单按照类型来做处理：类型为数字就做加法，类型为字符串就做拼接
            // 0 => 字符串，1 => 数字
            if(a.getType() == 1) {
                int num1 = BaseUtil.byte2int(a.getContent());
                int num2 = BaseUtil.byte2int(b.getContent());
                c.setContent(BaseUtil.int2byte(num1 + num2));
            } else if(a.getType() == 0) {
                String s1 = new String(a.getContent(), StandardCharsets.UTF_8);
                String s2 = new String(b.getContent(), StandardCharsets.UTF_8);
                String s3 = s1 + s2;
                c.setContent(s3.getBytes(StandardCharsets.UTF_8));
            }
    
            ByteBuffer buffer = concat(encode(a), encode(b), encode(c));
            
            ChatRoomManager.broadcast(new BinaryMessage(buffer));
        }
        
    }
    
    /**
     * 连接断开后执行
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("----------- 用户断开连接 -----------");
        log.info("会话id：{}", session.getId());
        log.info("断开原因：{}", status);
        log.info("\n");
        
        ChatRoomManager.remove(session.getId());
    }
    
    /**
     * 是否支持接收部分消息
     *
     * 可能是当接收的消息大小超过配置类{@link cn.xsirl.websocket.config.WebSocketConfig}设置的大小时，
     * 接受的消息是部分消息，具体细节暂时不清楚
     *
     * @return
     */
//    @Override
//    public boolean supportsPartialMessages() {
//        return true;
//    }
}
